package com.zzc.interview.judge;

import cn.hutool.json.JSONUtil;
import com.zzc.interview.common.ErrorCode;
import com.zzc.interview.exception.BusinessException;
import com.zzc.interview.judge.codesandbox.CodeSandBox;
import com.zzc.interview.judge.codesandbox.CodeSandBoxFactory;
import com.zzc.interview.judge.codesandbox.CodeSandboxProxy;
import com.zzc.interview.judge.codesandbox.judgeManager;
import com.zzc.interview.judge.codesandbox.model.ExecuteCodeRequest;
import com.zzc.interview.judge.codesandbox.model.ExecuteCodeResponse;
import com.zzc.interview.judge.strategy.JudgeContext;
import com.zzc.interview.model.dto.ojQuestion.JudgeCase;
import com.zzc.interview.model.dto.ojQuestion.JudgeConfig;
import com.zzc.interview.model.dto.questionSubmit.JudgeInfo;
import com.zzc.interview.model.entity.OjQuestion;
import com.zzc.interview.model.entity.QuestionSubmit;
import com.zzc.interview.model.enums.QuestionSubmitStatusEnum;
import com.zzc.interview.service.OjQuestionService;
import com.zzc.interview.service.QuestionSubmitService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class JudgeServiceImpl implements JudgeService {

    @Resource
    private QuestionSubmitService questionSubmitService;

    @Resource
    private OjQuestionService questionService;

    @Value("${codesandbox.type: example}")
    String type;

    @Transactional
    @Override
    public QuestionSubmit doJudge(long questionSubmitId) {
        // 根据id获取题目传入题目
        QuestionSubmit questionSubmit = questionSubmitService.getById(questionSubmitId);
        // 判断题目合法性
        // 提交信息不存在
        if (questionSubmit == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "提交信息不存在");
        }
        // 题目不存在
        OjQuestion question = questionService.getById(questionSubmit.getQuestionId());
        if (question == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "题目不存在");
        }
        // 题目正在waiting
        if (QuestionSubmitStatusEnum.WAITING.getText().equals(questionSubmit.getStatus())) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "正在判题，请等待");
        }
        // 更改判题状态
        QuestionSubmit questionUpdate = new QuestionSubmit();
        questionUpdate.setId(questionSubmit.getId());
        questionUpdate.setStatus(QuestionSubmitStatusEnum.RUNNING.getValue());
        boolean ok = questionSubmitService.updateById(questionUpdate);
        // 题目状态更新错误
        if (!ok) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "题目状态更新错误");
        }

        // 调用沙箱，获取执行结果
        CodeSandBox codeSandBox = CodeSandBoxFactory.newInstance(type);
        CodeSandboxProxy codeSandboxProxy = new CodeSandboxProxy(codeSandBox);

        // 填充请求信息
        ExecuteCodeRequest executeCodeRequest = new ExecuteCodeRequest();
        List<JudgeCase> judgeCase = JSONUtil.toList(question.getJudgeCase(), JudgeCase.class);
        List<String> inputList = judgeCase.stream().map(JudgeCase::getInput).collect(Collectors.toList());
        JudgeConfig judgeConfig = JSONUtil.toBean(question.getJudgeConfig(), JudgeConfig.class);

        executeCodeRequest.setInputList(inputList);
        executeCodeRequest.setCode(questionSubmit.getCode());
        executeCodeRequest.setLanguage(questionSubmit.getLanguage());
        executeCodeRequest.setMemoryLimit(judgeConfig.getMemoryLimit());

        // 根据沙箱的执行结果，设置题目的判题状态和信息
        ExecuteCodeResponse executeCodeResponse = codeSandboxProxy.executeCode(executeCodeRequest);
        List<String> outputList = executeCodeResponse.getOutputList();
        JudgeInfo judgeInfo = executeCodeResponse.getJudgeInfo(); // 判题服务给赋值了一次，这个accepted没什么用
        String judgeInfoStr = JSONUtil.toJsonStr(judgeInfo);

        JudgeContext judgeContext = new JudgeContext();
        judgeContext.setStatus(executeCodeResponse.getStatus());
        judgeContext.setInputList(inputList);
        judgeContext.setJudgeCaseList(judgeCase);
        judgeContext.setJudgeInfo(judgeInfo);
        judgeContext.setOutputList(outputList);
        judgeContext.setQuestion(question);
        judgeContext.setQuestionSubmit(questionSubmit);

        judgeInfo = judgeManager.doJudge(judgeContext); // 调用对应类型的判题服务
        judgeInfoStr = JSONUtil.toJsonStr(judgeInfo);

        // 修改数据库中的判题结果
        questionUpdate = new QuestionSubmit();
        questionUpdate.setId(questionSubmit.getId());
        questionUpdate.setStatus(QuestionSubmitStatusEnum.SUCCEED.getValue());
        questionUpdate.setJudgeInfo(judgeInfoStr);
        ok = questionSubmitService.updateById(questionUpdate);
        if (!ok) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "题目状态更新错误");
        }

        QuestionSubmit questionSubmitResult = questionSubmitService.getById(questionSubmit.getId());
        return questionSubmitResult;
    }
}
